/*
 * Reksio - Memory Map Editor
 * Copyright (C) 2023 CERN
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 * In applying this licence, CERN does not waive the privileges and immunities
 * granted to it by virtue of its status as an Intergovernmental Organization or
 * submit itself to any jurisdiction.
 */

#ifndef MEMORYNODE_H
#define MEMORYNODE_H
#include "attribute.h"
#include "attributecontainer.h"
#include "validator.h"
#include <string>
#include <list>
#include <map>
#include <memory>
#include <deque>
#include <QMetaType>

class SchemaValidator; // fwd decl
class ValidatorNode; // fwd decl
class AttributeValidator; // fwd decl

class MemoryNode
{
public:
    explicit MemoryNode(const std::string& type = "");
    MemoryNode(const MemoryNode& rhs);
    MemoryNode& operator=(const MemoryNode& rhs);
    MemoryNode& operator=(MemoryNode&& rhs);
    MemoryNode(MemoryNode&& rhs);

    bool operator==(const MemoryNode& rhs) const;

    void addChild(std::unique_ptr<MemoryNode>&& child);
    void addChild(std::unique_ptr<MemoryNode>&& child, const int& position);
    void addChild(MemoryNode* child);
    void addChild(MemoryNode* child, const int& position);
    std::unique_ptr<MemoryNode> removeChild(MemoryNode* child);
    std::unique_ptr<MemoryNode> removeChild(const int& position);
    void removeChildren();
    bool moveChildren(int sourcePosition, int count, MemoryNode* targetParent, int destPosition);

    int index() const;
    bool isValid(const bool recursive = true) const;
    bool validate(const bool recursive = true);

    const std::string getName() const;

    const std::list<std::string> nodeLocation() const;
    const std::list<std::string> typeLocation() const;
    MemoryNode* getRoot() const;
    std::vector<MemoryNode*> getAllChildren() const;
    MemoryNode* getChild(const std::string& type) const;
    MemoryNode* getChild(const std::vector<std::string>& type) const;
    bool hasChild(const std::string& type) const;
    bool hasChild(const std::vector<std::string>& type) const;

    int childCount() const;

    static void bind(MemoryNode* root_node, ValidatorNode* validator_node);
    static std::pair<std::unique_ptr<MemoryNode>, std::vector<std::string>> fromFile(const std::string& filename, const YAML::Node& schema, ValidatorNode* validator);
    static void save(const MemoryNode* root_node, const std::string& filename);
    void save(const std::string& filename) const;

    bool isAttributeSequence() const;
    bool isChildrenSequence() const;
    bool isSpecialSequence() const;

    // python validation
    void setPythonValidationResut(const bool result);
    bool pythonValidationResult() const;
    bool hasPythonValidator() const;

    const std::vector<std::pair<Attribute*, std::vector<INodeRuleValidator*>>> getFailedValidators() const;
    std::vector<AttributeValidator*> getMissingAttributes() const;

    // getters and setters
    const std::string& getType() const;
    void setType(const std::string& type);

    AttributeContainer* getAttributeContainer() const;

    const std::deque<std::unique_ptr<MemoryNode>>& getChildren() const;

    ValidatorNode* getValidator() const;
    void setValidator(ValidatorNode* new_validator);

    MemoryNode* getParent() const;
    void setParent(MemoryNode* new_parent);

    bool isSavable() const;
    void setSavable(bool is_savable);

    bool isEditable() const;
    void setEditable(bool is_editable);

    bool isDeprecated() const;
    bool hasDeprecated() const;

    std::vector<AttributeContainer*> getDeprecatedAttributeContainers() const;
    std::vector<Attribute*> getDeprecatedAttributes() const;

private:
    std::string _type;
    std::deque<std::unique_ptr<MemoryNode>> children;
    std::unique_ptr<AttributeContainer> attribute_container;
    ValidatorNode* validator;
    MemoryNode* parent = nullptr;
    bool savable = true; // if item should be saved
    bool movable = true; // if item can be moved
    bool removable = true; // if item can be removed
    bool duplicatable = true; // if item can be duplicated
    bool editable = true; // if item (and it's children) can be edited
    void updateParent();
    bool _py_validation_result = true;
};

std::ostream& operator<<(std::ostream& stream, const MemoryNode& memory_node);
Q_DECLARE_METATYPE(MemoryNode*)



#endif // MEMORYNODE_H
